#include "socketworker.h"
#include<QThread>
#include<QDateTime>
SocketWorker::SocketWorker(QObject *parent)
    : QObject{parent}
{
    m_tcp = new QTcpSocket(this);
    m_timer=new QTimer(this);
    m_tableTimer=new QTimer(this);
    m_onlineTimer=new QTimer(this);
    m_downLoad=false;
    //客户端连接服务器
    connect(m_tcp,&QTcpSocket::connected,this,[=](){
        emit sendTipMessage(1,"tcpClient","服务器连接成功！");
    });

    //与服务器断开连接
    connect(m_tcp, &QTcpSocket::disconnected, this, [=](){
        if (m_tcp) {
            m_tcp->close();
        }
        emit sendTipMessage(2,"tcpClient","服务器已断开连接！");
    });

    //处理服务器发送的数据
    connect(m_tcp,&QTcpSocket::readyRead,this,&SocketWorker::onReadyRead);

    //刷新表格
    connect(m_tableTimer, &QTimer::timeout, this, &SocketWorker::flushTable);

    //上传文件
    connect(m_timer, &QTimer::timeout, this, &SocketWorker::uploadFileData);

    //上线通知
    // connect(m_onlineTimer, &QTimer::timeout, this, &SocketWorker::onlineNotice);
}

SocketWorker::~SocketWorker()
{

}

void SocketWorker::handleAddFriendResult(bool isAgree,const QString&addName, const QString&usrName)
{
    qDebug()<<"添加好友反馈-当前线程："<<QThread::currentThread();
    PDU *pdu=mkPDU(0);
    strncpy(pdu->caData, addName.toStdString().c_str(), 32);           // 被加好友者用户名
    strncpy(pdu->caData + 32,usrName.toStdString().c_str(), 32);        // 加好友者用户名
    if(isAgree){              //同意添加好友
        pdu->uiMsgType=ENUM_MSG_TYPE_ADD_FRIEND_AGREE;
    }else {         //不同意添加好友
        pdu->uiMsgType=ENUM_MSG_TYPE_ADD_FRIEND_DISAGREE;
    }
    m_tcp->write((char*)pdu,pdu->uiPDULen);

    free(pdu);
    pdu=NULL;
}


//连接服务器
void SocketWorker::connectToServer(const QString &ip, quint16 port)
{
    m_tcp->connectToHost(ip, port);
}

void SocketWorker::flushTable()
{
    m_tableTimer->stop();
    emit flushSearchPage();
}

//上传文件数据（本机-->服务器）
void SocketWorker::uploadFileData()
{
    //等待1s后开始传文件
    m_timer->stop();
    qint64 currentUpload=0;
    QFile file(m_upLoadFilePath);       //获取待上传文件路径
    if(!file.open(QIODevice::ReadOnly)) // 只读形式打开文件
    {
        // 打开失败
        emit sendTipMessage(3,"mainWindow","打开文件失败！");
    }
    // 二进制形式传输文件
    char *pBuffer = new char[4096]; // 4096个字节读写效率更高
    qint64 iActualSize = 0;         // 实际读取文件内容大小
    while(true)
    {
        iActualSize = file.read(pBuffer, 4096); // 读数据，返回值是实际读取数据大小
        if (iActualSize > 0 && iActualSize <= 4096)
        {
            currentUpload+=iActualSize;
            int percent=currentUpload*100/m_uploadFileSize;
            emit setProgressBarVal(percent);
            m_tcp->write(pBuffer, iActualSize);
        }
        else if (iActualSize == 0)
        {
            qDebug()<<"发送完成~~~~";
            break;
        }
        else
        {
            emit sendTipMessage(3,"mainWindow","上传文件失败！");
            break;
        }
    }
    file.close();
    delete [] pBuffer;
    pBuffer = NULL;
    m_uploadFileSize=0;
    m_upLoadFilePath.clear();
}

void SocketWorker::onlineNotice()
{
    qDebug()<<"上线通知-当前线程："<<QThread::currentThread();
    m_onlineTimer->stop();
    PDU *pdu=mkPDU(0);
    pdu->uiMsgType=ENUM_MSG_TYPE_USR_ONLINE_NOTICE;
    strncpy(pdu->caData,m_usrName.toStdString().c_str(),32);
    // 发送二进制数据包
    m_tcp->write((char*)pdu,pdu->uiPDULen);
    // 释放内存
    free(pdu);
    pdu=NULL;
}

//注册
void SocketWorker::usrRegister(const QString &usrName, const QString &password)
{
    qDebug()<<"注册-当前线程："<<QThread::currentThread();
    PDU *pdu=mkPDU(0);
    pdu->uiMsgType=ENUM_MSG_TYPE_REGIST_REQUEST;
    /**
         *  strncpy 用于将源字符串的前 n 个字符复制到目标缓冲区中
         *  char *strncpy(char *dest, const char *src, size_t n);
         *  dest: 目标缓冲区（需预分配足够空间） src: 源字符串 n：最大复制字符数
         *
         */
    strncpy(pdu->caData,usrName.toStdString().c_str(),32);
    strncpy(pdu->caData+32,password.toStdString().c_str(),32);
    // 发送二进制数据包
    m_tcp->write((char*)pdu,pdu->uiPDULen);
    // 释放内存
    free(pdu);
    pdu=NULL;
}
//登录
void SocketWorker::usrLogIn(const QString &usrName, const QString &password)
{
    qDebug()<<"登录-当前线程："<<QThread::currentThread();
    m_usrName=usrName;           //更新当前用户名
    m_password=password;
    PDU *pdu=mkPDU(0);
    pdu->uiMsgType=ENUM_MSG_TYPE_LOGIN_REQUEST;
    /**
         *  strncpy 用于将源字符串的前 n 个字符复制到目标缓冲区中
         *  char *strncpy(char *dest, const char *src, size_t n);
         *  dest: 目标缓冲区（需预分配足够空间） src: 源字符串 n：最大复制字符数
         *
         */
    strncpy(pdu->caData,usrName.toStdString().c_str(),32);
    strncpy(pdu->caData+32,password.toStdString().c_str(),32);
    // 发送二进制数据包
    m_tcp->write((char*)pdu,pdu->uiPDULen);
    // 释放内存
    free(pdu);
    pdu=NULL;
}

//注销
void SocketWorker::usrLogOff()
{
    qDebug()<<"注销-当前线程："<<QThread::currentThread();
    PDU *pdu=mkPDU(0);
    pdu->uiMsgType=ENUM_MSG_TYPE_LOGOFF_REQUEST;
    strncpy(pdu->caData,m_usrName.toStdString().c_str(),32);
    // 发送二进制数据包
    m_tcp->write((char*)pdu,pdu->uiPDULen);
    // 释放内存
    free(pdu);
    pdu=NULL;

}


//根据用户名查找用户
void SocketWorker::searchUsrByName(const QString &name)
{
    qDebug()<<"模糊查找用户-当前线程："<<QThread::currentThread();
    PDU *pdu = mkPDU(0);
    pdu -> uiMsgType = ENUM_MSG_TYPE_SEARCH_USR_REQUEST;
    strncpy(pdu -> caData, name.toStdString().c_str(), 32);  //搜索用户名
    strncpy(pdu->caData + 32, m_usrName.toStdString().c_str(), 32); //本机用户名
    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}
//添加用户
void SocketWorker::addUsr(const QString &addName)
{
    qDebug()<<"添加好友-当前线程："<<QThread::currentThread();
    PDU* pdu = mkPDU(0);
    pdu -> uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_REQUEST;
    strncpy(pdu->caData, addName.toStdString().c_str(), 32);
    strncpy(pdu->caData + 32, m_usrName.toStdString().c_str(), 32);
    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}

//刷新好友列表
void SocketWorker::flushFriendList()
{
    qDebug()<<"刷新好友列表-当前线程："<<QThread::currentThread();
    //获取用户名，发送给服务器
    QString strName=m_usrName;
    PDU *pdu=mkPDU(0);
    pdu->uiMsgType=ENUM_MSG_TYPE_FLUSH_FRIEND_REQUEST;
    strncpy(pdu->caData, strName.toStdString().c_str(), 32);
    m_tcp->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu=NULL;
}

//获取在线好友列表
void SocketWorker::onlineFriendList()
{
    qDebug()<<"获取在线好友列表-当前线程："<<QThread::currentThread();
    //获取用户名，发送给服务器
    PDU *pdu=mkPDU(0);
    pdu->uiMsgType=ENUM_MSG_TYPE_GET_ONLINE_FRIEND_REQUEST;
    strncpy(pdu->caData, m_usrName.toStdString().c_str(), 32);
    m_tcp->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu=NULL;
}

void SocketWorker::shareFileToFriend(const QList<QString> &friendList,const QString &fileName)
{
    qDebug()<<"分享文件-当前线程："<<QThread::currentThread();
    int friendSize=friendList.size();
    //使用UTF-8编码转换
    QByteArray pathData = m_curDirPath.toUtf8();
    int pathDataLen=pathData.size();
    QByteArray fileNameData = fileName.toUtf8();
    int fileNameDataLen=fileNameData.size();
    unsigned int totalMsgLen = friendSize*32 + 8 + pathDataLen + fileNameDataLen;

    PDU *pdu=mkPDU(totalMsgLen);
    pdu->uiMsgType=ENUM_MSG_TYPE_SHARE_FILE_REQUEST;
    strncpy(pdu->caData, m_usrName.toStdString().c_str(), 32);
    strncpy(pdu->caData+32, QString::number(friendSize).toStdString().c_str(), 32);
    char *p = pdu->caMsg;

    for(int i=0;i<friendSize;i++){
        strncpy((char*)pdu->caMsg+i*32,
                friendList.at(i).toStdString().c_str(),
                32);
        p+=32;
    }

    memcpy(p, &pathDataLen, sizeof(int));
    p += sizeof(int);
    memcpy(p, pathData.constData(), pathDataLen);
    p+=pathDataLen;
    memcpy(p, &fileNameDataLen, sizeof(int));
    p += sizeof(int);
    memcpy(p, fileNameData.constData(), fileNameDataLen);

    m_tcp->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu=NULL;

}
//删除好友
void SocketWorker::deleteFriend(const QString &deleteName)
{
    qDebug()<<"删除好友-当前线程："<<QThread::currentThread();
    PDU *pdu=mkPDU(0);
    pdu -> uiMsgType = ENUM_MSG_TYPE_DELETE_FRIEND_REQUEST;
    strncpy(pdu -> caData, m_usrName.toStdString().c_str(), 32);
    strncpy(pdu -> caData+32, deleteName.toStdString().c_str(), 32);
    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu=NULL;
}
//群聊
void SocketWorker::groupChatRquset(const QString &msg)
{
    qDebug()<<"群聊好友-当前线程："<<QThread::currentThread();
    //使用UTF-8编码转换
    QByteArray msgData = msg.toUtf8();

    PDU*pdu=mkPDU(msgData.size());
    pdu->uiMsgType=ENUM_MSG_TYPE_GROUP_CHAT_REQUEST;
    strncpy(pdu->caData,m_usrName.toStdString().c_str(),32);

    //消息内容(支持中文)
    memcpy(pdu->caMsg, msgData.constData(), msgData.size());

    m_tcp->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu=NULL;
}

//私聊
void SocketWorker::privateChatRequest(const QString &chatName, const QString &msg)
{
    qDebug()<<"私聊好友-当前线程："<<QThread::currentThread();
    //使用UTF-8编码转换
    QByteArray msgData = msg.toUtf8();

    PDU*pdu=mkPDU(msgData.size());
    pdu->uiMsgType=ENUM_MSG_TYPE_PRIVATE_CHAT_REQUEST;
    strncpy(pdu->caData,m_usrName.toStdString().c_str(),32);           //本机name
    strncpy(pdu->caData+32,chatName.toStdString().c_str(),32);          //目标name
    //发送内容(支持中文)
    memcpy(pdu->caMsg,msgData.constData(),msgData.size());
    m_tcp->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu=NULL;
}
//用户下线
void SocketWorker::usrOffline()
{
    qDebug()<<"私聊好友-当前线程："<<QThread::currentThread();
    PDU*pdu=mkPDU(0);
    pdu->uiMsgType=ENUM_MSG_TYPE_USR_OFFLINE_REQUEST;
    strncpy(pdu -> caData, m_usrName.toStdString().c_str(), 32);       //用户名放在caData
    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu=NULL;
}
//新建文件夹
void SocketWorker::createNewDir(const QString &createDirName)
{
    //使用UTF-8编码转换
    QByteArray pathData = m_curDirPath.toUtf8();
    QByteArray dirNameData = createDirName.toUtf8();
    unsigned int totalMsgLen = 8 + pathData.size() + dirNameData.size();
    PDU *pdu=mkPDU(totalMsgLen);
    pdu -> uiMsgType = ENUM_MSG_TYPE_CREATE_DIR_REQUEST;
    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;

    // 写入第一个字符串的长度
    int pathLen = pathData.size();
    memcpy(ptr, &pathLen, sizeof(int));
    ptr += sizeof(int);

    // 写入第一个字符串数据
    memcpy(ptr, pathData.constData(), pathLen);
    ptr += pathLen;

    // 写入第二个字符串的长度
    int nameLen = dirNameData.size();
    memcpy(ptr, &nameLen, sizeof(int));
    ptr += sizeof(int);

    // 写入第二个字符串数据
    memcpy(ptr, dirNameData.constData(), nameLen);

    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu=NULL;
}

//刷新文件夹
void SocketWorker::flushCurrentDir()
{
    //使用UTF-8编码转换
    QByteArray pathData = m_curDirPath.toUtf8();
    PDU *pdu = mkPDU(pathData.size());
    pdu -> uiMsgType = ENUM_MSG_TYPE_FLUSH_DIR_REQUEST;
    //发送内容(支持中文)
    memcpy(pdu->caMsg,pathData.constData(),pathData.size());
    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}

//删除文件/文件夹
void SocketWorker::deleteDirFile(const QString& dir_FileName)
{
    QByteArray pathData = m_curDirPath.toUtf8();
    QByteArray deleteNameData=dir_FileName.toUtf8();
    unsigned int totalMsgLen = 8 + pathData.size() + deleteNameData.size();
    PDU *pdu = mkPDU(totalMsgLen);
    pdu -> uiMsgType = ENUM_MSG_TYPE_DELETE_DIR_FILE_REQUEST;
    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;

    //写入第一个字符串的长度
    int pathLen=pathData.size();
    memcpy(ptr, &pathLen, sizeof(int));
    ptr += sizeof(int);

    // 写入第一个字符串数据
    memcpy(ptr, pathData.constData(), pathLen);
    ptr += pathLen;

    // 写入第二个字符串的长度
    int nameLen = deleteNameData.size();
    memcpy(ptr, &nameLen, sizeof(int));
    ptr += sizeof(int);

    // 写入第二个字符串数据
    memcpy(ptr, deleteNameData.constData(), nameLen);

    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}

//重命名文件/文件夹
void SocketWorker::renameDirFile(const QString &oldName, const QString &newName)
{
    QByteArray oldNameData =oldName.toUtf8();           //旧文件名
    QByteArray newNameData=newName.toUtf8();            //新文件名
    QByteArray pathData = m_curDirPath.toUtf8();        //当前路径
    unsigned int totalMsgLen=12+oldNameData.size()+newNameData.size()+pathData.size();
    PDU*pdu=mkPDU(totalMsgLen);
    pdu -> uiMsgType = ENUM_MSG_TYPE_RENAME_DIR_FILE_REQUEST;
    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;

    //写入第一个字符串长度
    int pathLen=pathData.size();
    memcpy(ptr,&pathLen,sizeof(int));
    ptr+=sizeof(int);

    // 写入第一个字符串数据
    memcpy(ptr, pathData.constData(), pathLen);
    ptr += pathLen;

    //写入第二个字符串长度
    int oldNameLen=oldNameData.size();
    memcpy(ptr,&oldNameLen,sizeof(int));
    ptr+=sizeof(int);

    //写入第二个字符串数据
    memcpy(ptr,oldNameData.constData(),oldNameLen);
    ptr+=oldNameLen;

    //写入第三个字符串长度
    int newNameLen=newNameData.size();
    memcpy(ptr,&newNameLen,sizeof(int));
    ptr+=sizeof(int);

    //写入第三个字符串数据
    memcpy(ptr,newNameData.constData(),newNameLen);

    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}

//进入文件夹
void SocketWorker::entryRequest(const QString &dirName)
{
    QByteArray pathData = m_curDirPath.toUtf8();
    QByteArray entryNameData=dirName.toUtf8();
    unsigned int totalMsgLen = 8 + pathData.size() + entryNameData.size();
    PDU *pdu = mkPDU(totalMsgLen);
    pdu -> uiMsgType = ENUM_MSG_TYPE_ENTER_DIR_REQUEST;
    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;
    //写入第一个字符串的长度
    int pathLen=pathData.size();
    memcpy(ptr, &pathLen, sizeof(int));
    ptr += sizeof(int);
    // 写入第一个字符串数据
    memcpy(ptr, pathData.constData(), pathLen);
    ptr += pathLen;
    // 写入第二个字符串的长度
    int nameLen = entryNameData.size();
    memcpy(ptr, &nameLen, sizeof(int));
    ptr += sizeof(int);
    // 写入第二个字符串数据
    memcpy(ptr, entryNameData.constData(), nameLen);
    m_entryPath=QString("%1/%2").arg(m_curDirPath).arg(dirName);
    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}
//返回上一级
void SocketWorker::backDirRequest()
{
    if(m_curDirPath == m_rootDirPath)
    {
        emit sendTipMessage(2,"mainWindow","已经为根目录！");
        return;
    }
    int index = m_curDirPath.lastIndexOf("/");
    m_curDirPath = m_curDirPath.remove(index, m_curDirPath.size() - index);
    flushCurrentDir();
}

//上传文件
void SocketWorker::uploadFileRequest(const QString &upLoadFilePath)
{
    //获取到需要上传的文件的绝对路径
    m_upLoadFilePath=upLoadFilePath;
    QFile file(m_upLoadFilePath);
    QString fileName = QFileInfo(m_upLoadFilePath).fileName();  // 获得文件名
    qint64 fileSize = file.size(); // 获得文件大小
    m_uploadFileSize=fileSize;
    qDebug()<<"当前文件路径："<<m_curDirPath<<",文件名："<<fileName<<",文件大小："<<QString::number(fileSize)+"字节";
    QByteArray pathData = m_curDirPath.toUtf8();        // 当前路径
    QByteArray nameData =fileName.toUtf8();           // 文件名
    unsigned int totalMsgLen=8+pathData.size()+nameData.size()+sizeof(qint64);
    PDU*pdu=mkPDU(totalMsgLen);
    pdu -> uiMsgType = ENUM_MSG_TYPE_UPLOAD_FILE_REQUEST;

    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;
    //写入当前路径长度
    int pathLen=pathData.size();
    memcpy(ptr,&pathLen,sizeof(int));
    ptr+=sizeof(int);

    // 写入当前路径数据
    memcpy(ptr, pathData.constData(), pathLen);
    ptr += pathLen;

    //写入文件名长度
    int nameLen=nameData.size();
    memcpy(ptr,&nameLen,sizeof(int));
    ptr+=sizeof(int);

    //写入文件名数据
    memcpy(ptr,nameData.constData(),nameLen);
    ptr+=nameLen;

    //写入文件大小
    memcpy(ptr,&fileSize,sizeof(qint64));

    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}

//下载文件请求
void SocketWorker::downloadFileRequest(const QString &fileName, const QString &saveFilePath)
{
    //路径不为空，然后赋值
    m_downLoadFilePath=saveFilePath;

    //存放文件名+当前路径
    QByteArray pathData = m_curDirPath.toUtf8();        // 当前路径
    QByteArray nameData =fileName.toUtf8();           // 文件名
    unsigned int totalMsgLen = 8 + pathData.size() + nameData.size();
    PDU *pdu = mkPDU(totalMsgLen);
    pdu->uiMsgType=ENUM_MSG_TYPE_DOWNLOAD_FILE_REQUEST;

    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;
    //写入第一个字符串的长度
    int pathLen=pathData.size();
    memcpy(ptr, &pathLen, sizeof(int));
    ptr += sizeof(int);
    // 写入第一个字符串数据
    memcpy(ptr, pathData.constData(), pathLen);
    ptr += pathLen;
    // 写入第二个字符串的长度
    int nameLen = nameData.size();
    memcpy(ptr, &nameLen, sizeof(int));
    ptr += sizeof(int);
    // 写入第二个字符串数据
    memcpy(ptr, nameData.constData(), nameLen);

    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}

//移动文件请求
void SocketWorker::moveFileRequest(const QString &sourcePath, const QString &fileName, const QString &targetPath)
{
    QByteArray sourcePathData=sourcePath.toUtf8();
    QByteArray targetPathData=targetPath.toUtf8();
    QByteArray fileNameData=fileName.toUtf8();
    PDU*pdu=mkPDU(12+sourcePathData.size()+targetPathData.size()+fileNameData.size());
    pdu->uiMsgType=ENUM_MSG_TYPE_MOVE_FILE_REQUEST;
    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;

    //写入原文件路径长度
    int sourcePathLen=sourcePathData.size();
    memcpy(ptr,&sourcePathLen,sizeof(int));
    ptr+=sizeof(int);

    // 写入原文件路径
    memcpy(ptr, sourcePathData.constData(), sourcePathLen);
    ptr += sourcePathLen;

    //写入目标路径长度
    int targetPathLen=targetPathData.size();
    memcpy(ptr,&targetPathLen,sizeof(int));
    ptr+=sizeof(int);

    //写入目标路径
    memcpy(ptr,targetPathData.constData(),targetPathLen);
    ptr+=targetPathLen;

    //写入文件名长度
    int fileNameLen=fileNameData.size();
    memcpy(ptr,&fileNameLen,sizeof(int));
    ptr+=sizeof(int);

    //写入第三个字符串数据
    memcpy(ptr,fileNameData.constData(),fileNameLen);

    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}

void SocketWorker::handleShareFileFeedBack(bool isAgree, const QString &path)
{
    qDebug()<<"分享文件反馈-当前线程："<<QThread::currentThread();
    QByteArray sourcePathData=path.toUtf8();
    int sourcePathLen=sourcePathData.size();
    PDU*pdu=NULL;

    if(isAgree){              //同意接收文件
        pdu=mkPDU(4+sourcePathLen);
        char *ptr=pdu->caMsg;
        pdu->uiMsgType=ENUM_MSG_TYPE_RECV_SHARE_FILE_AGREE;
        //写入原文件路径长度
        memcpy(ptr,&sourcePathLen,sizeof(int));
        ptr+=sizeof(int);
        memcpy(ptr, sourcePathData.constData(), sourcePathLen);
    }else {         //不同意接收文件
        pdu=mkPDU(0);
        pdu->uiMsgType=ENUM_MSG_TYPE_RECV_SHARE_FILE_DISAGREE;
    }

    m_tcp->write((char*)pdu,pdu->uiPDULen);
    free(pdu);
    pdu=NULL;
}

void SocketWorker::handleModifyInfo(const QString &oldUsrName, const QString &newUsrName, const QString &newPwd)
{
    qDebug()<<"旧用户名--"<<oldUsrName<<",新用户名："<<newUsrName<<"，新密码："<<newPwd;
    QByteArray oldUsrNameData=oldUsrName.toUtf8();
    QByteArray newUsrNameData=newUsrName.toUtf8();
    QByteArray newPwdData=newPwd.toUtf8();
    PDU*pdu=mkPDU(12+oldUsrNameData.size()+newUsrNameData.size()+newPwdData.size());
    pdu->uiMsgType=ENUM_MSG_TYPE_MODIFY_REQUEST;
    // 写入数据到柔性数组
    char* ptr = pdu->caMsg;
    int oldUsrNameLen=oldUsrNameData.size();
    memcpy(ptr,&oldUsrNameLen,sizeof(int));
    ptr+=sizeof(int);
    memcpy(ptr, oldUsrNameData.constData(), oldUsrNameLen);
    ptr += oldUsrNameLen;

    int newUsrNameLen=newUsrNameData.size();
    memcpy(ptr,&newUsrNameLen,sizeof(int));
    ptr+=sizeof(int);
    memcpy(ptr, newUsrNameData.constData(), newUsrNameLen);
    ptr += newUsrNameLen;

    int newPwdLen=newPwdData.size();
    memcpy(ptr,&newPwdLen,sizeof(int));
    ptr+=sizeof(int);

    memcpy(ptr,newPwdData.constData(),newPwdLen);


    m_tcp->write((char*)pdu, pdu -> uiPDULen);
    free(pdu);
    pdu = NULL;
}



//获取数据
void SocketWorker::onReadyRead()
{
    //当前为下载文件状态
    if(m_downLoad){
        //接收数据
        QByteArray buffer=m_tcp->readAll();
        m_file.write(buffer);           //文件之前被打开过，向文件中写入数据
        m_recved+=buffer.size();
        int percent=m_recved*100/m_total;
        emit setProgressBarVal(percent);
        if(m_total==m_recved){
            m_file.close();
            m_downLoad=false;
            emit setProgessBarClosedEn(true);
            emit hideProgressBar();
            emit setStatusBar("文件下载成功！");
            emit sendTipMessage(1,"mainWindow","文件下载成功！");
        }else if(m_total<m_recved){
            m_file.close();
            m_downLoad=false;
            emit hideProgressBar();
            emit setStatusBar("文件下载失败！");
            emit sendTipMessage(3,"mainWindow","文件下载失败！");
        }

    }else{
        unsigned int uiPDULen=0;
        // 总数据大小
        m_tcp->read((char*)&uiPDULen,sizeof(unsigned int));
        // 实际消息大小，sizeof(PDU)只会计算结构体大小，而不是分配的大小
        unsigned int uiMsgLen=uiPDULen-sizeof(PDU);
        PDU*pdu=mkPDU(uiMsgLen);
        m_tcp->read((char *)pdu+sizeof(unsigned int),uiPDULen-sizeof(unsigned int));
        switch(pdu->uiMsgType)
        {
        case ENUM_MSG_TYPE_REGIST_RESPOND:          //注册回复
        {
            if(strcmp(pdu->caData,REGIST_OK)==0){
                emit sendTipMessage(1,"tcpClient","注册成功！");
            }else if(strcmp(pdu->caData,REGIST_FAILED)==0){
                emit sendTipMessage(2,"tcpClient","用户已存在，无法重复注册！");
            }
            break;
        }
        case ENUM_MSG_TYPE_LOGIN_RESPOND:          //登录回复
        {
            if(strcmp(pdu->caData,LOGIN_OK)==0){
                m_rootDirPath=QString("./%1").arg(m_usrName);
                m_curDirPath=m_rootDirPath;         //登录时将当前目录自动设置为根目录
                emit sendTipMessage(1,"tcpClient","登录成功！");
                emit logInSuccessSignal(m_usrName);
            }else if(strcmp(pdu->caData,LOGIN_FAILED)==0){
                emit sendTipMessage(3,"tcpClient","账号或密码错误或已登录！");
            }
            break;
        }
        case ENUM_MSG_TYPE_LOGOFF_RESPOND:{         //注销回复
            emit closeMainWinSignal();
            if(strcmp(pdu->caData,LOGOFF_OK)==0){
                emit sendTipMessage(1,"tcpClient","注销成功！",1500);
            }else if(strcmp(pdu->caData,LOGOFF_FAILED)==0){
                emit sendTipMessage(3,"tcpClient","注销失败！",1500);
            }
            break;
        }

        case ENUM_MSG_TYPE_MODIFY_RESPOND:{         //修改用户信息回复
            emit closeMainWinSignal();
            if(strcmp(pdu->caData,MODIFYINFO_OK)==0){
                emit sendTipMessage(1,"tcpClient","修改成功！",1500);
            }else if(strcmp(pdu->caData,MODIFYINFO_FAILED)==0){
                emit sendTipMessage(3,"tcpClient","修改失败！",1500);
            }
            break;
        }
        case ENUM_MSG_TYPE_ALL_ONLINE_USRS_RESPOND:          //所有在线用户回复
        {

            break;
        }
        case ENUM_MSG_TYPE_GET_ONLINE_FRIEND_RESPOND:           //所有在线好友回复
        {
            //PDU 解析
            int itemNum=pdu->uiMsgLen/32;
            char caTmp[32]={'\0'};
            QList<QString> usrList;
            for(int i = 0; i < itemNum; i++)
            {
                strncpy(caTmp, (char*)(pdu -> caMsg) + 32 * i, 32);
                if(strcmp(caTmp, m_usrName.toStdString().c_str()) != 0){
                    usrList.append(caTmp);
                }
            }

            emit sendOnlineFriendList(usrList);
            break;
        }
        case ENUM_MSG_TYPE_SEARCH_USR_RESPOND:          //查找用户回复
        {
            char *p = pdu->caMsg;
            QList<UserInfo> resultList;
            while (p < pdu->caMsg + pdu->uiMsgLen) {
                int nameLen = 0, online = 0, isFriend = 0;
                UserInfo info;
                memcpy(&nameLen, p, sizeof(int));
                p += sizeof(int);

                memcpy(&online, p, sizeof(int));
                p += sizeof(int);

                memcpy(&isFriend, p, sizeof(int));
                p += sizeof(int);

                QString name = QString::fromUtf8(p, nameLen);
                p += nameLen;

                info.name=name;
                info.online = online;
                info.isFriend = isFriend;
                resultList.append(info);
            }
            emit sendSearchData(resultList);
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_REQUEST:          //转发过来的添加好友请求（别人加我）
        {
            char caAddName[32]={'\0'};        //接收方(本人)name
            char caUsrName[32]={'\0'};         //发送方name
            strncpy(caAddName,pdu->caData,32);
            strncpy(caUsrName,pdu->caData+32,32);
            QString addName=QString::fromUtf8(caAddName);
            QString usrName=QString::fromUtf8(caUsrName);
            emit addFriendSignal(addName,usrName);
            break;
        }
        case ENUM_MSG_TYPE_FLUSH_FRIEND_AND_TABLE_RESPOND:     //同意对方的添加好友请求后,刷新好友列表和表格
        {
            flushFriendList();
            m_tableTimer->start(500);
            break;
        }
        /************************************************************************/
        case ENUM_MSG_TYPE_ADD_FRIEND_RESPOND:          //添加好友回复
        {
            if(strcmp(UNKNOW_ERROR, pdu -> caData)==0){
                emit sendTipMessage(3,"mainWindow","系统出错！");
            }
            else if(strcmp(EXISTED_FRIEND, pdu -> caData)==0){
                emit sendTipMessage(2,"mainWindow","双方已经为好友！");
            }
            else if(strcmp(ADD_FRIEND_OK, pdu -> caData)==0){
                emit sendTipMessage(1,"mainWindow","添加好友请求已发送！");
            }
            else if(strcmp(ADD_FRIEND_OFFLINE, pdu -> caData)==0){
                emit sendTipMessage(2,"mainWindow","用户不在线！");
            }
            else if(strcmp(ADD_FRIEND_NOEXIST, pdu -> caData)==0){
                emit sendTipMessage(2,"mainWindow","用户不存在！");
            }
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_AGREE:      // 对方同意加好友
        {
            emit sendTipMessage(1,"mainWindow", QString("%1 已同意您的好友申请！").arg(pdu -> caData));
            flushFriendList();
            m_tableTimer->start(500);
            break;
        }
        case ENUM_MSG_TYPE_ADD_FRIEND_DISAGREE:   // 对方拒绝加好友
        {
            emit sendTipMessage(3,"mainWindow",QString("%1 已拒绝您的好友申请！").arg(pdu -> caData));
            break;
        }

        case ENUM_MSG_TYPE_FLUSH_FRIEND_RESPOND:    // 刷新好友响应
        {
            //PDU 解析这一块
            int size = pdu -> uiMsgLen / 36; // 注意是36，32 name + 4 online
            char caName[32] = {'\0'};
            char caOnline[4] = {'\0'};
            QMap<QString,QString>friendList;
            for(int i = 0; i < size; i++)
            {
                strncpy(caName, (char*)(pdu -> caMsg) + i * 36, 32);
                strncpy(caOnline, (char*)(pdu -> caMsg) + i * 36 + 32 , 4);
                friendList.insert(caName,caOnline);
            }
            emit updateFriList(friendList);
            break;
        }

        case ENUM_MSG_TYPE_DELETE_FRIEND_RESPOND:{              //删除好友回复

            //******这里需要改
            emit sendTipMessage(1,"mainWindow",pdu -> caData);
            flushFriendList();
            m_tableTimer->start(500);
            break;
        }
        case ENUM_MSG_TYPE_DELETE_FRIEND_REQUEST:       // 处理服务器转发过来的删除好友请求
        {
            char usrName[32]; // 获取发送方用户名
            strncpy(usrName, pdu -> caData, 32);
            emit sendTipMessage(1,"mainWindow",QString("%1 已删除与您的好友关系！").arg(usrName));
            flushFriendList();      //删除后刷新列表
            m_tableTimer->start(500);
            break;
        }

        case ENUM_MSG_TYPE_PRIVATE_CHAT_REQUEST:{           //处理转发过来的私聊请求
            char chatName[32]={'\0'};
            strncpy(chatName,pdu->caData,32);      //获取对方用户名
            QString strChatName=chatName;
            QString msg = QString::fromUtf8(pdu->caMsg, pdu->uiMsgLen);
            emit sendPriChatMsg(strChatName,msg);
            break;
        }

        case ENUM_MSG_TYPE_GROUP_CHAT_REQUEST:{                 //处理转发过来的群聊请求
            QString chatName=(char*)pdu->caData;
            // 指定长度防止越界
            QString msg = QString::fromUtf8(pdu->caMsg, pdu->uiMsgLen);
            QDateTime current = QDateTime::currentDateTime();
            QString strTime = current.toString("yyyy-MM-dd HH:mm:ss");
            QString strMsg = QString("["+chatName+"]"+strTime);
            emit sendGroupChatMsg(msg,strMsg);
            break;
        }
        /****************************************************************************/
        case ENUM_MSG_TYPE_CREATE_DIR_RESPOND:{         //创建文件夹回复
            if(strcmp(DIR_NAME_EXIST, pdu -> caData)==0){
                emit sendTipMessage(3,"mainWindow","文件夹已存在,请勿重复创建！");
            }else if(strcmp(CREATE_DIR_OK, pdu -> caData)==0){
                emit sendTipMessage(1,"mainWindow","文件夹创建成功！");
            }else if(strcmp(DIR_NO_EXIST, pdu -> caData)==0){
                emit sendTipMessage(3,"mainWindow","当前目录不存在！");
            }
            flushCurrentDir();      //刷新文件夹
            break;
        }

        case ENUM_MSG_TYPE_FLUSH_DIR_RESPOND:{          //刷新文件夹回复
            QMap<QString,int> fileList;
            char* p = pdu->caMsg;
            int total = pdu->uiMsgLen;
            while (p < pdu->caMsg + total) {
                int nameLen=0;
                int fileType=0;
                memcpy(&nameLen, p, sizeof(int));
                p += sizeof(int);
                memcpy(&fileType, p, sizeof(int));
                p += sizeof(int);
                QString fileName = QString::fromUtf8(p, nameLen);
                p += nameLen;
                fileList.insert(fileName,fileType);
            }
            emit updateFileList(fileList);
            emit setStatusBar("当前所在文件夹："+m_curDirPath);
            break;
        }
        case ENUM_MSG_TYPE_DELETE_DIR_FILE_RESPOND:{         //删除文件/文件夹回复
            //五种情况
            if(strcmp(PATH_NOT_EXIST, pdu -> caData)==0){
                emit sendTipMessage(3,"mainWindow","删除-当前路径不存在！");
            }else if(strcmp(DELETE_DIR_OK, pdu -> caData)==0){
                emit sendTipMessage(1,"mainWindow","删除-文件夹删除成功！");
            }else if(strcmp(DELETE_DIR_FAILED, pdu -> caData)==0){
                emit sendTipMessage(3,"mainWindow","删除-文件夹删除失败！");
            }else if(strcmp(DELETE_FILE_OK, pdu -> caData)==0){
                emit sendTipMessage(1,"mainWindow","删除-文件删除成功！");
            }else if(strcmp(DELETE_FILE_FAILED, pdu -> caData)==0){
                emit sendTipMessage(3,"mainWindow","删除-文件删除失败！");
            }
            flushCurrentDir();      //删除后刷新
            break;
        }

        case ENUM_MSG_TYPE_RENAME_DIR_FILE_RESPOND:{        //重命名文件/文件夹回复
            if(strcmp(RENAME_OK, pdu -> caData)==0){
                emit sendTipMessage(1,"mainWindow","文件-重命名成功！");
            }else if(strcmp(RENAME_FAILED, pdu -> caData)==0){
                emit sendTipMessage(3,"mainWindow","文件-重命名失败！");
            }
            flushCurrentDir(); //重命名后刷新
            break;
        }

        case ENUM_MSG_TYPE_ENTER_DIR_RESPOND:{      // 进入文件夹回复
            if(strcmp(ENTER_DIR_OK,pdu->caData)==0){
                m_curDirPath=m_entryPath;          //进入文件夹时更新当前目录
                emit setStatusBar("当前所在文件夹："+m_curDirPath);
                QMap<QString,int> fileList;
                char* p = pdu->caMsg;
                int total = pdu->uiMsgLen;
                while (p < pdu->caMsg + total) {
                    int nameLen=0;
                    int fileType=0;
                    memcpy(&nameLen, p, sizeof(int));
                    p += sizeof(int);
                    memcpy(&fileType, p, sizeof(int));
                    p += sizeof(int);
                    QString fileName = QString::fromUtf8(p, nameLen);
                    p += nameLen;

                    fileList.insert(fileName,fileType);
                }
                emit updateFileList(fileList);
            }
            else{
                emit sendTipMessage(3,"mainWindow","非文件夹！");
            }
            break;
        }

        case ENUM_MSG_TYPE_UPLOAD_FILE_RESPOND:{            //上传文件回复
            if(strcmp(UPLOAD_FILE_START, pdu -> caData) == 0) {
                qDebug()<<"开始上传文件内容~~~~~";
                emit setProgressBarTitle("文件上传");
                emit showProgressBar();
                emit setStatusBar("文件："+m_upLoadFilePath+"上传中...");
                m_timer->start(1000);
            }else if(strcmp(UPLOAD_FILE_OK, pdu -> caData) == 0){
                qDebug()<<"文件上传成功~~~~~";
                //在这里发送可关闭进度条窗口信号
                emit setProgessBarClosedEn(true);
                emit hideProgressBar();
                emit setStatusBar("文件上传成功！");
                emit sendTipMessage(1,"mainWindow","文件上传成功！");
                flushCurrentDir();             //上传后刷新
            }else if(strcmp(UPLOAD_FILE_FAILED, pdu -> caData) == 0) {
                qDebug()<<"文件上传失败~~~~~";
                emit hideProgressBar();
                emit setStatusBar("文件上传失败！");
                emit sendTipMessage(3,"mainWindow","文件上传失败！");
            }else if(strcmp(OPEN_FILE_FAILED,pdu->caData)==0){
                qDebug()<<"打开文件失败~~~~~";
                emit hideProgressBar();
                emit setStatusBar("打开文件失败！");
                emit sendTipMessage(3,"mainWindow","打开文件失败！");
            }
            break;
        }

        case ENUM_MSG_TYPE_DOWNLOAD_FILE_RESPOND:{              //下载文件回复
            if(strcmp(DOWNLOAD_FILE_START, pdu -> caData) == 0) {
                emit setProgressBarTitle("文件下载");
                emit showProgressBar();
                //从柔性数组中获取数据
                char* ptr = pdu->caMsg;
                // 读取文件名
                int nameLen = 0;
                memcpy(&nameLen, ptr, sizeof(int));
                ptr += sizeof(int);
                QString fileName = QString::fromUtf8(ptr, nameLen);
                ptr += nameLen;
                //读取文件大小
                qint64 fileSize=0;
                memcpy(&fileSize, ptr, sizeof(qint64));

                //代表收到的是有效数据
                if(nameLen>0){
                    m_downLoad=true;
                    m_total=fileSize;
                    m_recved=0;
                    m_file.setFileName(m_downLoadFilePath);
                    emit setStatusBar("文件："+m_downLoadFilePath+"下载中...");

                    if(!m_file.open(QIODevice::WriteOnly)){
                        //只是获取文件保存的路径
                        emit setStatusBar("获得保存文件的路径失败！");
                        emit sendTipMessage(3,"mainWindow","获得保存文件的路径失败！");
                    }
                }else{
                    emit setStatusBar("下载文件失败！");
                    emit sendTipMessage(3,"mainWindow","下载文件失败！");
                }
            }else if(strcmp(OPEN_FILE_FAILED, pdu -> caData) == 0){
                emit setStatusBar("打开文件失败！");
                emit sendTipMessage(3,"mainWindow","文件打开失败！");
            }else if(strcmp(NON_FILE, pdu -> caData) == 0){
                emit setStatusBar("当前选中单元为文件夹！");
                emit sendTipMessage(2,"mainWindow","文件下载-当前选中单元为文件夹！");
            }

            break;
        }

        case ENUM_MSG_TYPE_MOVE_FILE_RESPOND:{                  //移动文件回复
            if(strcmp(MOVE_FILE_OK, pdu -> caData) == 0){
                emit sendTipMessage(1,"mainWindow","文件移动成功！");
                flushCurrentDir();
            }else if(strcmp(MOVE_FILE_FAILED, pdu -> caData) == 0){
                emit sendTipMessage(3,"mainWindow","文件移动失败！");
            }else if(strcmp(MOVE_DIR_OK, pdu -> caData) == 0){
                emit sendTipMessage(1,"mainWindow","文件夹移动成功！");
                flushCurrentDir();
            }else if(strcmp(MOVE_DIR_FAILED, pdu -> caData) == 0){
                emit sendTipMessage(3,"mainWindow","文件夹移动失败！");
            }
            break;
        }

        case ENUM_MSG_TYPE_SHARE_FILE_REQUEST:       //转发过来的分享文件请求
        {
            char caUsrName[32] = {'\0'};
            strncpy(caUsrName, pdu -> caData, 32);
            QString usrName=QString::fromUtf8(caUsrName);
            char *ptr=pdu->caMsg;
            int pathDataLen = 0;
            memcpy(&pathDataLen, ptr, sizeof(int));
            ptr += sizeof(int);
            QString pathData = QString::fromUtf8(ptr, pathDataLen);

            emit handleShareFileSignal(usrName,pathData);
            break;
        }
        case ENUM_MSG_TYPE_SHARE_FILE_RESPOND:          //分享文件回复
        {
            if(strcmp(SHARE_FILE_OK, pdu -> caData) == 0){
                emit sendTipMessage(1,"mainWindow","文件已分享！");
            }else if(strcmp(SHARE_DIR_OK, pdu -> caData) == 0){
                emit sendTipMessage(1,"mainWindow","文件夹已分享！");
            }
            break;
        }
        case ENUM_MSG_TYPE_SHARE_FILE_SUCCESS:
        {
            if(strcmp(RECV_FILE_OK, pdu -> caData) == 0){
                emit sendTipMessage(1,"mainWindow","接收文件成功！\n\t文件已存放到根目录",1500);
                flushCurrentDir();      //刷新文件夹
            }else if(strcmp(RECV_FILE_FAILED, pdu -> caData) == 0){
                emit sendTipMessage(3,"mainWindow","接收文件失败！\n\t文件重名！",1500);
            }else if(strcmp(RECV_DIR_OK, pdu -> caData) == 0){
                emit sendTipMessage(1,"mainWindow","接收文件夹成功！\n\t文件夹已存放到根目录",1500);
                flushCurrentDir();      //刷新文件夹
            }else if(strcmp(RECV_DIR_FAILED, pdu -> caData) == 0){
                emit sendTipMessage(3,"mainWindow","接收文件夹失败！\n\t文件夹重名！",1500);
            }
            break;
        }

        case ENUM_MSG_TYPE_USR_ONLINE_NOTICE:        //用户上线通知
        {
            char caUsrName[32] = {'\0'};
            strncpy(caUsrName, pdu -> caData, 32);
            QString usrName=QString::fromUtf8(caUsrName);
            emit sendTipMessage(1,"mainWindow","用户 "+usrName+" 已上线");
            flushFriendList();
            m_tableTimer->start(800);
            break;
        }
        case ENUM_MSG_TYPE_USR_OFFLINE_NOTICE:        //用户下线通知
        {
            char caUsrName[32] = {'\0'};
            strncpy(caUsrName, pdu -> caData, 32);
            QString usrName=QString::fromUtf8(caUsrName);
            emit sendTipMessage(1,"mainWindow","用户 "+usrName+" 已下线");
            flushFriendList();
            m_tableTimer->start(800);
            break;
        }

        default:
            break;
        }

        free(pdu);
        pdu=NULL;
    }

}

QString SocketWorker::password() const
{
    return m_password;
}

void SocketWorker::setPassword(const QString &newPassword)
{
    m_password = newPassword;
}

QString SocketWorker::usrName() const
{
    return m_usrName;
}

void SocketWorker::setUsrName(const QString &newUsrName)
{
    m_usrName = newUsrName;
}

QString SocketWorker::curDirPath() const
{
    return m_curDirPath;
}

void SocketWorker::setCurDirPath(const QString &newCurDirPath)
{
    m_curDirPath = newCurDirPath;
}

